//
// AWS Manager - A free AWS console application demonstrating advanced concepts
// Copyright (C) 2008-2010 Sean O'Dell. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.awsmanager.common;

import com.awsmanager.utils.ProcessText;
import com.sun.data.provider.impl.ObjectListDataProvider;
import com.sun.data.provider.RowKey;
import com.xerox.amazonws.ec2.EC2Exception;
import com.xerox.amazonws.ec2.SnapshotInfo;
import com.xerox.amazonws.ec2.VolumeInfo;
import com.xerox.amazonws.sdb.Domain;
import com.xerox.amazonws.sdb.Item;
import com.xerox.amazonws.sdb.ItemAttribute;
import com.xerox.amazonws.sdb.QueryWithAttributesResult;
import com.xerox.amazonws.sdb.SDBException;
import com.xerox.amazonws.sdb.SimpleDB;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Sean ODell
 */
public class EBSSnapshotDataProvider extends ObjectListDataProvider {

    private ArrayList ebsSnapshotList = new ArrayList();
    private EC2Connection ec2connection;
    private SimpleDB simpleDB;
    private Domain sdbdomain = null;

    /** Creates a new instance of AddressDataProvider */
    public EBSSnapshotDataProvider() {
        setList(ebsSnapshotList);
        setObjectType(EBSSnapshot.class);
    }

    public void load(EC2Connection ec2connection, SDBConnection sdbconnection) {

        clearObjectList();

        if (ec2connection == null) {
            this.ec2connection = null;
            return;
        } else {
            this.ec2connection = ec2connection;
        }

        List<ItemAttribute> sdbattributes = null;
        String sdbdomainname = null;
        String sdbdomainsuffix = "";
        Map sdbSnapshotItems = null;
        Map sdbVolumeItems = null;


        ArrayList<String> sdbattributesList = new ArrayList<String>();
        sdbattributesList.add("type");
        sdbattributesList.add("name");
        sdbattributesList.add("description");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamefirst");
        sdbattributesList.add("ownerdept");

        ArrayList<String> sdbattributesName = new ArrayList<String>();
        sdbattributesName.add("name");

        sdbdomain = null;

        if ((simpleDB = sdbconnection.getsimpleDB()) != null) {

            sdbdomainname = sdbconnection.getsdbdomain() + sdbdomainsuffix;

            try {
                sdbdomain = simpleDB.getDomain(sdbdomainname);
            } catch (SDBException ex) {
                sdbdomain = null;
                Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            try {
                sdbdomain.getItem("test").getAttributes();
            } catch (SDBException ex) {
                try {
                    sdbdomain = simpleDB.createDomain(sdbdomainname);
                } catch (SDBException ex1) {
                    Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex1);
                }
            }

            QueryWithAttributesResult queryResult = null;
            String nextToken = "";

            if (sdbdomain != null) {
                try {
                    queryResult = sdbdomain.selectItems("select * from "
                            + sdbdomainname + " where type = 'snapshot'", nextToken, true);
                } catch (SDBException ex) {
                    Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                }
                if (queryResult != null) {
                    sdbSnapshotItems = queryResult.getItems();
                }

                try {
                    queryResult = sdbdomain.selectItems("select * from "
                            + sdbdomainname + " where type = 'volume'", nextToken, true);
                } catch (SDBException ex) {
                    Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                }
                if (queryResult != null) {
                    sdbVolumeItems = queryResult.getItems();
                }
            }
        }

        List<String> params = new ArrayList<String>();
        ArrayList<String> ec2Regions = ec2connection.getEc2RegionNames();
        EC2Region ec2RegionInfo = null;

        for (String ec2Region : ec2Regions) {

            ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Region);

            List<SnapshotInfo> ebsSnapshots = null;

            try {
                ebsSnapshots = ec2RegionInfo.getRegionConnection().describeSnapshots(params);
            } catch (EC2Exception ex) {
                Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            for (SnapshotInfo snap : ebsSnapshots) {

                EBSSnapshot ebsSnapshot = new EBSSnapshot();

                ebsSnapshot.setSnapRegion(ec2Region);
                ebsSnapshot.setsnapshotId(snap.getSnapshotId());
                ebsSnapshot.setvolumeId(snap.getVolumeId());
                ebsSnapshot.setstatus(snap.getStatus());
                ebsSnapshot.setstartTime(snap.getStartTime());
                ebsSnapshot.setprogress(snap.getProgress());
                ebsSnapshot.setownerID(snap.getOwnerId());
                ebsSnapshot.setdescription(snap.getDescription());
                ebsSnapshot.setownerAlias(snap.getOwnerAlias());
                ebsSnapshot.setvolumeSize(snap.getVolumeSize());

                if (sdbdomain != null) {
                    sdbattributes = (List<ItemAttribute>) sdbSnapshotItems.get(snap.getSnapshotId());
                    if (sdbattributes != null) {
                        if (sdbattributes.size() > 0) {
                            for (ItemAttribute attribute : sdbattributes) {
                                String attributename = attribute.getName();
                                if (attributename.equals("name")) {
                                    ebsSnapshot.setsnapname(attribute.getValue());
                                } else if (attributename.equals("description")) {
                                    ebsSnapshot.setsnapdesc(attribute.getValue());
                                } else if (attributename.equals("ownernamelast")) {
                                    ebsSnapshot.setsnapownernamelast(attribute.getValue());
                                } else if (attributename.equals("ownernamefirst")) {
                                    ebsSnapshot.setsnapownernamefirst(attribute.getValue());
                                } else if (attributename.equals("ownerdept")) {
                                    ebsSnapshot.setsnapownerdept(attribute.getValue());
                                }
                            }
                        }
                    }
                }

                // get the name of the snapshot from which the volume was created.
                if (ebsSnapshot.getvolumeId() != null) {
                    if (!ebsSnapshot.getvolumeId().equals("")
                            && sdbdomain != null) {
                        sdbattributes = (List<ItemAttribute>) sdbVolumeItems.get(ebsSnapshot.getvolumeId());
                        if (sdbattributes != null) {
                            if (sdbattributes.size() > 0) {
                                for (ItemAttribute attribute : sdbattributes) {
                                    String attributename = attribute.getName();
                                    if (attributename.equals("name")) {
                                        ebsSnapshot.setVolname(attribute.getValue());
                                    }
                                }
                            }
                        }
                    }
                }
                getList().add(ebsSnapshot);
            }
        }
    }

    public EBSSnapshot getSnapshot(RowKey rowKey) {
        EBSSnapshot ebsSnapshot = (EBSSnapshot) getObject(rowKey);
        return ebsSnapshot;
    }

    public EBSSnapshot getSnapshot(String id) {
        for (int i = 0; i < ebsSnapshotList.size(); i++) {
            EBSSnapshot ebsSnapshot = (EBSSnapshot) ebsSnapshotList.get(i);
            if (ebsSnapshot.getsnapshotId().equals(id)) {
                return ebsSnapshot;
            }
        }
        return null;
    }

    public int getSnapshotIndex(String id) {
        for (int i = 0; i < ebsSnapshotList.size(); i++) {
            EBSSnapshot ebsSnapshot = (EBSSnapshot) ebsSnapshotList.get(i);
            if (ebsSnapshot.getsnapshotId().equals(id)) {
                return i;
            }
        }
        return -1;
    }

    public String createSnapshot(Map createSnapsInfo, Map cloneMetaData) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        ProcessText processText = new ProcessText();
        String statusMsg = new String();
        SnapshotInfo snapshotInfo = null;
        ArrayList createSnapsList = (ArrayList) createSnapsInfo.get("volRowKeys");
        EBSVolumeDataProvider ebsVolumeDataProvider = (EBSVolumeDataProvider) createSnapsInfo.get("volDataProvider");

        Item sdbitemsnap = null;
        Item sdbitemvol = null;

        List<ItemAttribute> sdbattributes = null;
        ArrayList<String> sdbattributesList = new ArrayList<String>();
        sdbattributesList.add("name");
        sdbattributesList.add("description");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamefirst");
        sdbattributesList.add("ownerdept");

        // create a snapshot for each volume selected
        for (int i = 0; i < createSnapsList.size(); i++) {

            // get the volume id and volume region from the volume data provider
            EBSVolume ebsVolume = ebsVolumeDataProvider.getVolume((RowKey) createSnapsList.get(i));
            String volid = ebsVolume.getvolumeId();

            // get the connecton to the volume region
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ebsVolume.getVolumeRegion());

            statusMsg = statusMsg + "\nVolume ID: " + volid + "\n";

            // create the snapshot from the volume
            try {
                snapshotInfo = ec2RegionInfo.getRegionConnection().createSnapshot(volid, "Snapshot");
            } catch (EC2Exception ex) {
                Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                if (ex.getMessage() != null) {
                    statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                }
            }

            // if the create snapshot command was successful, provide status and
            // copy the metadata if clone option selected
            if (snapshotInfo != null) {
                statusMsg = statusMsg + "  Snapshot ID        : " + snapshotInfo.getSnapshotId() + "\n";
                statusMsg = statusMsg + "  Snapshot status    : " + snapshotInfo.getStatus() + "\n";
                statusMsg = statusMsg + "  Snapshot start time: " + (String) processText.calToDateStr(snapshotInfo.getStartTime()) + "\n";

                // clone metadata for the new snapshot copying the metadata from the volume
                Boolean clonemetadataflag = (Boolean) cloneMetaData.get("cloneVol");
                if (clonemetadataflag) {
                    if (sdbdomain != null) {
                        // get the metadata for the volume
                        try {
                            sdbitemvol = sdbdomain.getItem(volid);
                            sdbattributes = sdbitemvol.getAttributes(sdbattributesList);
                        } catch (SDBException ex) {
                            Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                            if (ex.getMessage() != null) {
                                statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                            }
                        }
                        // copy the volume attributes to the snapshot
                        if (sdbattributes != null) {
                            try {
                                sdbitemsnap = sdbdomain.getItem(snapshotInfo.getSnapshotId());
                                sdbattributes.add(new ItemAttribute("type", (String) "snapshot", true));
                                sdbattributes.add(new ItemAttribute("createtime", (String) processText.calToDateStr(snapshotInfo.getStartTime()), true));
                                sdbitemsnap.putAttributes(sdbattributes);
                            } catch (SDBException ex) {
                                Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                                if (ex.getMessage() != null) {
                                    statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                                }
                            }
                        }
                    }
                }
            }
        }
        return statusMsg;
    }

    public String deleteSnapshot(Map deleteSnapsInfo) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        String statusMsg = new String();
        ArrayList deleteSnapsList = (ArrayList) deleteSnapsInfo.get("snapRowKeys");

        for (int i = 0; i < deleteSnapsList.size(); i++) {

            // get the snapshot id and snapshot region
            EBSSnapshot ebsSnapshot = getSnapshot((RowKey) deleteSnapsList.get(i));
            String snapid = ebsSnapshot.getsnapshotId();
            String snapRegion = ebsSnapshot.getSnapRegion();

            // get the connecton to the region
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(snapRegion);

            try {
                ec2RegionInfo.getRegionConnection().deleteSnapshot(snapid);
                statusMsg = statusMsg + "Deleteing snapshot: " + snapid + "\n";
            } catch (Exception e) {
                e.printStackTrace();
                if (e.getMessage() != null) {
                    statusMsg = statusMsg + "Error: " + e.getMessage() + "\n";
                }
            }
        }
        return statusMsg;
    }

    public String updateSnapshot(Map snapMetaData) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        int snapIndex = -1;
        String statusMsg = new String();
        Item sdbitem = null;
        List<ItemAttribute> sdbattributes = new ArrayList<ItemAttribute>();

        String snapid = (String) snapMetaData.get("snapid");

        if (sdbdomain != null) {
            try {
                sdbitem = sdbdomain.getItem(snapid);

                sdbattributes.add(new ItemAttribute("type", (String) snapMetaData.get("type"), true));
                sdbattributes.add(new ItemAttribute("createtime", (String) snapMetaData.get("snapcreatetime"), true));
                sdbattributes.add(new ItemAttribute("name", (String) snapMetaData.get("snapname"), true));
                sdbattributes.add(new ItemAttribute("description", (String) snapMetaData.get("snapdesc"), true));
                sdbattributes.add(new ItemAttribute("ownernamelast", (String) snapMetaData.get("snapownernamelast"), true));
                sdbattributes.add(new ItemAttribute("ownernamefirst", (String) snapMetaData.get("snapownernamefirst"), true));
                sdbattributes.add(new ItemAttribute("ownerdept", (String) snapMetaData.get("snapownerdept"), true));

                sdbitem.putAttributes(sdbattributes);

                EBSSnapshot ebsSnapshot = getSnapshot(snapid);
                snapIndex = getSnapshotIndex(snapid);

                ebsSnapshot.setsnapname((String) snapMetaData.get("snapname"));
                ebsSnapshot.setsnapdesc((String) snapMetaData.get("snapdesc"));
                ebsSnapshot.setsnapownernamelast((String) snapMetaData.get("snapownernamelast"));
                ebsSnapshot.setsnapownernamefirst((String) snapMetaData.get("snapownernamefirst"));
                ebsSnapshot.setsnapownerdept((String) snapMetaData.get("snapownerdept"));

                ebsSnapshotList.set(snapIndex, ebsSnapshot);

            } catch (SDBException ex) {
                Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return statusMsg;
    }

    public String createVolsFromSnaps(Map createVolsFromSnapsInfo, Map cloneMetaData) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if (this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        ProcessText processText = new ProcessText();
        String statusMsg = new String();
        Integer volCount = (Integer) createVolsFromSnapsInfo.get("volCount");
        String volSize = (String) createVolsFromSnapsInfo.get("volSize");
        String volZone = (String) createVolsFromSnapsInfo.get("volZone");
        ArrayList createVolsFromSnapsList = (ArrayList) createVolsFromSnapsInfo.get("snapsRowKeys");

        Item sdbitemsnap = null;
        Item sdbitemvol = null;

        List<ItemAttribute> sdbattributes = null;
        ArrayList<String> sdbattributesList = new ArrayList<String>();
        sdbattributesList.add("name");
        sdbattributesList.add("description");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamelast");
        sdbattributesList.add("ownernamefirst");
        sdbattributesList.add("ownerdept");

        EC2Region ec2RegionInfo = null;
        Map ec2ZoneToRegion = ec2connection.getEc2ZoneToRegion();

        for (int j = 1; j <= volCount; j++) {

            for (int i = 0; i < createVolsFromSnapsList.size(); i++) {

                EBSSnapshot ebsSnapshot = getSnapshot((RowKey) createVolsFromSnapsList.get(i));
                String snapID = ebsSnapshot.getsnapshotId();
                String snapRegion = ebsSnapshot.getSnapRegion();
                String volRegion = (String) ec2ZoneToRegion.get(volZone);
                ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(snapRegion);

                statusMsg = statusMsg + "\nSnapshot ID: " + snapID + "\n";

                if (!volRegion.equals(snapRegion)) {
                    statusMsg = statusMsg + "  Error: zone specified for volume does not exist in snapshot region.\n";
                    statusMsg = statusMsg + "         Volume zone: " + volZone + ", "
                            + "Snapshot region: " + snapRegion + "\n";
                } else {

                    VolumeInfo volumeInfo = null;
                    try {
                        volumeInfo = ec2RegionInfo.getRegionConnection().createVolume(volSize, snapID, volZone);
                    } catch (EC2Exception ex) {
                        Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                        if (ex.getMessage() != null) {
                            statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                        }
                    }

                    if (volumeInfo != null) {
                        statusMsg = statusMsg + "  Volume ID         : " + volumeInfo.getVolumeId() + "\n";
                        statusMsg = statusMsg + "  Volume size       : " + volumeInfo.getSize() + "\n";
                        statusMsg = statusMsg + "  Availability zone : " + volumeInfo.getZone() + "\n";
                        statusMsg = statusMsg + "  Volume status     : " + volumeInfo.getStatus() + "\n";
                        statusMsg = statusMsg + "  Volume create time: " + processText.calToDateStr(volumeInfo.getCreateTime()) + "\n";

                        Boolean clonemetadataflag = (Boolean) cloneMetaData.get("cloneSnap");
                        if (clonemetadataflag) {
                            if (sdbdomain != null) {
                                try {
                                    sdbitemsnap = sdbdomain.getItem(snapID);
                                    sdbattributes = sdbitemsnap.getAttributes(sdbattributesList);
                                } catch (SDBException ex) {
                                    Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                                    if (ex.getMessage() != null) {
                                        statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                                    }
                                }
                                if (sdbattributes != null) {
                                    try {
                                        sdbitemvol = sdbdomain.getItem(volumeInfo.getVolumeId());
                                        sdbattributes.add(new ItemAttribute("type", (String) "volume", true));
                                        sdbattributes.add(new ItemAttribute("size", (String) volumeInfo.getSize(), true));
                                        sdbattributes.add(new ItemAttribute("createtime", (String) processText.calToDateStr(volumeInfo.getCreateTime()), true));
                                        sdbitemvol.putAttributes(sdbattributes);
                                    } catch (SDBException ex) {
                                        Logger.getLogger(EBSSnapshotDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                                        if (ex.getMessage() != null) {
                                            statusMsg = statusMsg + "Error: " + ex.getMessage() + "\n";
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return statusMsg;
    }
}
